package org.chenbingkang.boot.common;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.*;

public class VODUtil {

    private static Logger logger = LoggerFactory.getLogger(VODUtil.class);

    /**
     * ffprobe -show_entries stream=width,height -select_streams v  -v quiet  -of json -i
     *
     * @param command
     * @throws IOException
     */
    public static String execResult(String command) throws IOException {
        logger.info("exec command : " + command);
        Process process = Runtime.getRuntime().exec(command);
        InputStream inputStream = process.getInputStream();
        String inputStreamStr = getStreamString(inputStream);
        logger.info("exec command : " + command + " input : " + inputStreamStr);
        return inputStreamStr;
    }

    /**
     * 按时间剪辑视频
     * @param input 需要剪辑的文件路径
     * @param output  剪辑完成以后输出的文件路径
     * @param start   剪辑开始时间
     * @param duration 持续时间
     * @return
     * @throws IOException
     */
    public static boolean editVOD(String input, String output, String start, int duration) throws IOException {
        String command = "ffmpeg -ss " + start + " -i " + input + " -t " + duration + " " + output;
        if (exec(command) == 0) {
            return true;
        }
        return false;
    }

    /**
     * 裁剪视频
     * @param input 需要裁剪的文件路径
     * @param output 裁剪完成以后输出的文件路径
     * @param x 表示裁剪区域的左上角x坐标
     * @param y 表示裁剪区域的左上角y坐标
     * @param width 裁剪后的宽度
     * @param height 裁剪后的高度
     * @return
     * @throws IOException
     */
    public static boolean cutVDO(String input, String output, int x, int y, int width, int height) throws IOException {
        String command = "ffmpeg -i " + input + "  -vf crop=" + width + ":" + height + ":" + x + ":" + y + " " + output;
        if (exec(command) == 0) {
            return true;
        }
        return false;
    }

    /**
     * 剪辑加裁剪视频
     * @param input
     * @param output
     * @param start
     * @param duration
     * @param x
     * @param y
     * @param width
     * @param height
     * @return
     * @throws IOException
     */
    public static boolean cutAndEditVDO(String input, String output, String start, int duration, int x, int y, int width, int height) throws IOException {
        String command = "ffmpeg -ss " + start + " -i " + input + " -t " + duration + " -vf crop=" + width + ":" + height + ":" + x + ":" + y + " " + output;
        if (exec(command) == 0) {
            return true;
        }
        return false;
    }

    /**
     * 视频截图
     * @param input 需要截图的视频路径
     * @param output 截图生成位置
     * @param start 需要截图的时间点
     * @param frames
     * @return
     * @throws IOException
     */
    public static boolean snapshotVOD(String input, String output, String start, int frames) throws IOException {
        String command = "ffmpeg -i " + input + " -ss " + start + " -vframes " + frames + " " + output;
        if (exec(command) == 0) {
            return true;
        }
        return false;
    }

    /**
     * 雪碧截图
     * @param input 需要截图的视频路径
     * @param output 截图生成位置
     * @return
     * @throws IOException
     */
    public static boolean spriteSnapshotVOD(String input, String output) throws IOException {
        String tmpDir = output + UUID.randomUUID().toString();
        try {
            Files.createDirectory(Paths.get(tmpDir));
            String command = "ffmpeg  -i " + input + " -vf fps=1 " + tmpDir + "/%d.png";
            if (exec(command) == 0) {
                mergeImage(tmpDir, output, 150, 150);
                return true;
            }
        } finally {
            deleteDir(new File(tmpDir));
        }
        return false;
    }

    private static void deleteDir(File file) {
        if (!file.exists()) {
            return;
        }
        if (file.isDirectory()) {
            for (File f : file.listFiles())
                deleteDir(f);
        }
        file.delete();
    }

    /**
     * 合并图片
     * @param dirname
     * @param out
     * @param width
     * @param height
     * @throws IOException
     */
    private static void mergeImage(String dirname, String out, int width, int height) throws IOException {
        File dir = new File(dirname);
        File[] files = dir.listFiles();
        Arrays.sort(files, new Comparator<File>() {
            @Override
            public int compare(File o1, File o2) {
                return o1.getName().split("\\.")[0].compareTo(o2.getName().split("\\.")[0]);
            }
        });
        List<BufferedImage> imageItemList = new ArrayList<>();
        for (File file : files) {
            BufferedImage image = ImageIO.read(file);
            imageItemList.add(image);
        }
        int totalWidth = width * 10;
        int totalHeight = (imageItemList.size() / 10 + 1) * height;
        BufferedImage resultImage = new BufferedImage(totalWidth, totalHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics = resultImage.createGraphics();
        for (int i = 0; i < imageItemList.size(); i++) {
            BufferedImage partImage = imageItemList.get(i);
            int row = i / 10;
            int column = i % 10;
            int x = column * width;
            int y = row * height;
            graphics.drawImage(partImage,
                    x, y, x + width, y + height,
                    0, 0, partImage.getWidth(), partImage.getHeight(),
                    null);
        }
        ImageIO.write(resultImage, "png", new File(out));

    }

    public static int exec(String command) throws IOException {
        logger.info("exec command : " + command);
        Process process = Runtime.getRuntime().exec(command);
        InputStream inputStream = process.getInputStream();
        String inputStreamStr = getStreamString(inputStream);
        logger.info("exec command : " + command + " input : " + inputStreamStr);
        String errorStreamStr = getStreamString(process.getErrorStream());
        logger.error("exec command : " + command + " error : " + errorStreamStr);
        return process.exitValue();
    }

    private static String getStreamString(InputStream inputStream) throws IOException {
        byte[] buffer = new byte[1024];
        StringBuilder sb = new StringBuilder();
        int count = -1;
        while ((count = inputStream.read(buffer)) != -1) {
            sb.append(new String(buffer, 0, count));
        }
        inputStream.close();
        return sb.toString();
    }

    public static void main(String... args) throws Exception {
        // editVOD("/Users/chenbingkang/Downloads/ffmpeg-test.mp4","/Users/chenbingkang/Downloads/ffmpeg-test18.mp4","00:00:03",5);
        // cutVDO("/Users/chenbingkang/Downloads/ffmpeg-test.mp4", "/Users/chenbingkang/Downloads/ffmpeg-test20.mp4", 0, 0, 320, 540);
        // cutAndEditVDO("/Users/chenbingkang/Downloads/ffmpeg-test.mp4", "/Users/chenbingkang/Downloads/ffmpeg-test30.mp4", "00:00:03", 5, 0, 0, 320, 540);
        // exec("ffprobe -show_entries stream=width,height -select_streams v  -v quiet  -of json -i /Users/chenbingkang/Downloads/ffmpeg-test.mp4\n");
        // spriteSnapshotVOD("/Users/chenbingkang/Downloads/ffmpeg-test.mp4", "/Users/chenbingkang/Downloads/ffmpeg-test43.png");
        // mergeImage("/Users/chenbingkang/Downloads/ffmpeg-test41.png56dcf1d3-a72e-47da-b7f1-cdee33ddd7a3","/Users/chenbingkang/Downloads/ffmpeg-test41.png",150,150);
        // snapshotVOD("/Users/chenbingkang/Downloads/ffmpeg-test.mp4","/Users/chenbingkang/Downloads/ffmpeg-test50.png","00:00:00",1);
    }
}
